﻿/****************************************************************************************************
	Copyright (C) 2010 RapidWebDev Organization (http://rapidwebdev.org)
	Author: Eunge, Legal Name: Jian Liu, Email: eunge.liu@RapidWebDev.org

	The GNU Library General Public License (LGPL) used in RapidWebDev is 
	intended to guarantee your freedom to share and change free software - to 
	make sure the software is free for all its users.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Library General Public License (LGPL) for more details.

	You should have received a copy of the GNU Library General Public License (LGPL)
	along with this program.  
	If not, see http://www.rapidwebdev.org/Content/ByUniqueKey/OpenSourceLicense
 ****************************************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
using RapidWebDev.Common;
using HttpStatusCode = System.Net.HttpStatusCode;
using Image = System.Drawing.Image;

namespace RapidWebDev.FileManagement.Web
{
	/// <summary>
	/// Http handler for downloading thumbnails of the files.
	/// </summary>
	public class ThumbnailDownloadHttpHandler : IHttpHandler
	{
		private static readonly IFileBindingApi fileBindingApi = SpringContext.Current.GetObject<IFileBindingApi>();

		/// <summary>
		/// You will need to configure this handler in the web.config file of your
		/// web and register it with IIS before being able to use it. For more information
		/// see the following link: http://go.microsoft.com/?linkid=8101007
		/// </summary>
		/// <value></value>
		/// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
		/// </returns>
		public bool IsReusable
		{
			// Return false in case your Managed Handler cannot be reused for another request.
			// Usually this would be false in case you have some state information preserved per request.
			get { return true; }
		}

		/// <summary>
		/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
		/// </summary>
		/// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
		public void ProcessRequest(HttpContext context)
		{
			Guid fileId = ResolveFileId(context);
			int width, height;
			if (Kit.IsEmpty(context.Request["Width"]) || !int.TryParse(((int)Unit.Parse(context.Request["Width"]).Value).ToString(), out width))
			{
				CompleteResponseWithError(context, HttpStatusCode.BadRequest, "The request is invalid.");
				return;
			}

			if (Kit.IsEmpty(context.Request["Height"]) || !int.TryParse(((int)Unit.Parse(context.Request["Height"]).Value).ToString(), out height))
			{
				CompleteResponseWithError(context, HttpStatusCode.BadRequest, "The request is invalid.");
				return;
			}

			if (!String.IsNullOrEmpty(context.Request.Headers["If-Modified-Since"]))
			{
				CultureInfo provider = CultureInfo.InvariantCulture;
				DateTime lastMod = DateTime.ParseExact(context.Request.Headers["If-Modified-Since"], "r", provider).ToLocalTime();
				if ((DateTime.Now - lastMod).TotalDays <= 30)
				{
					context.Response.StatusCode = (int)HttpStatusCode.NotModified;
					context.Response.StatusDescription = "Not Modified";
					return;
				}
			}

			Size thumbnailSize = new Size(width, height);
			IThumbnailApi thumbnailApi = SpringContext.Current.GetObject<IThumbnailApi>();
			ThumbnailFileHeadObject thumbnailFileHeadObject = null;

			try
			{
				thumbnailFileHeadObject = thumbnailApi.GetThumbnailFileHead(fileId, thumbnailSize);
			}
			catch
			{
				CompleteResponseWithError(context, HttpStatusCode.BadRequest, "The request is invalid.");
				return;
			}

			if (System.IO.File.Exists(thumbnailFileHeadObject.ThumbnailFilePath))
			{
				FileDownloadHttpHandler.AddDownloadHeaders(context, thumbnailFileHeadObject);

				context.Response.ContentType = "image/jpeg";
				context.Response.WriteFile(thumbnailFileHeadObject.ThumbnailFilePath);

				//Image image = Image.FromFile(thumbnailFileHeadObject);
				//image.Save(context.Response.OutputStream, ImageFormat.Jpeg);

				context.Response.Cache.SetCacheability(HttpCacheability.Public);
				context.Response.Cache.SetExpires(DateTime.Now.AddDays(30d));
				context.Response.Cache.SetLastModified(DateTime.Now);

				context.Response.Flush();
				context.Response.End();
				context.Response.Close();
				return;
			}

			CompleteResponseWithError(context, HttpStatusCode.ServiceUnavailable, "The service is unavailable at this moment.");
		}

		private static void CompleteResponseWithError(HttpContext context, System.Net.HttpStatusCode statusCode, string statusDescription)
		{
			context.Response.StatusCode = (int)statusCode;
			context.Response.StatusDescription = statusDescription;
			context.Response.End();
			context.Response.Close();
		}

		private static Guid ResolveFileId(HttpContext context)
		{
			try
			{
				return new Guid(context.Request["FileId"]);
			}
			catch
			{
			}

			Guid externObjectId = Guid.Empty;
			try
			{
				externObjectId = new Guid(context.Request["ExternalObjectId"]);
			}
			catch
			{
				CompleteResponseWithError(context, HttpStatusCode.NotFound, "Both file id and external object id of the thumbnail is invalid.");
				return Guid.Empty;
			}

			string relationshipType =  context.Request["RelationshipType"];
			IEnumerable<FileHeadObject> attachments = fileBindingApi.FindBoundFiles(externObjectId, relationshipType);
			return (from f in attachments
					orderby f.CreatedOn
					select f.Id).FirstOrDefault();
		}
	}
}